Skip to content

test(sca,workflows): pin routes, request bodies and wire tags - #69

Merged
aaearon merged 7 commits into
mainfrom
test/wire-contracts
Aug 16, 2026
Merged

test(sca,workflows): pin routes, request bodies and wire tags#69
aaearon merged 7 commits into
mainfrom
test/wire-contracts

Conversation

@aaearon

@aaearon aaearon commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Part 8 of 8. Base: test/isolation-harness (#63) — must merge first. Tests and docs only; no production change.

The headline

Renaming the accessCredentials JSON tag on internal/sca/models/elevate.go passed the entire repo suite. It is the single field grant env exists to deliver — rename it and every AWS elevation silently returns nil credentials. The existing tests only ever decoded "accessCredentials": null, and the service tests set the field to nil in Go structs the test itself marshalled, so the tag round-tripped trivially.

Now decoded from a raw JSON literal off the wire through ParseAWSCredentials, asserting all three values.

Also

  • All six checkResponse call sites in internal/workflows could be deleted undetected — the existing test only called the helper directly. A 500 decoded as an empty AccessRequest, so grant request submit printed a blank request and exited 0. The 500 fixture is deliberately designed to decode cleanly into every response model, so removing a guard yields a genuine silent success rather than an incidental decode error.
  • internal/workflows/logging_client.go had no test file at all, including its Authorization-redaction path, while the byte-identical SCA one was fully covered. It is on the live path.
  • Every SCA endpoint route except eligibility was unasserted; POST bodies were never inspected (the mock discarded them).
  • TestListSessions_WithCSPFilter was tautological — it asserted its own canned response. grant status --provider azure could have been filtering nothing.
  • FinalizeRequest could drop the approver's reason and lose the request ID from the route; the test asserted only HasSuffix(route, "/finalize").
  • The X-API-Version: 2.0 guard lived inside TestNewSCAAccessServiceDisablesTransientRetry, so a retry-motivated rename would have silently deleted it. Now its own named test.

A won't-fix that became a fix

The ISP service slug was unpinned because both retry tests overwrite client.BaseURL before issuing a request. I had allowed a documented won't-fix; the implementer pinned it instead, arguing the failure mode is total — every live request to the wrong host. Correct call.

Recorded for the next reviewer

Two rows were previously marked "not reproducible" because a Codex sandbox blocked loopback TCP. Both reproduce fine here. The ledger preamble now records that a loopback-blocked sandbox cannot refute a row, and that a bare deletion of DisableTransientRetry is a compile kill, not a test kill — the honest mutation is _ = sdkclient.DisableTransientRetry. That confusion cost two verification passes.

29/30 mutations killed (the survivor pre-existing and inert). Adversarial review performed (Codex credits exhausted; review by a Claude agent). All findings fixed — ledger only; no Go file changed.

@aaearon aaearon closed this Aug 15, 2026
@aaearon aaearon reopened this Aug 15, 2026
@aaearon
aaearon deleted the branch main August 16, 2026 07:34
@aaearon aaearon closed this Aug 16, 2026
@aaearon aaearon reopened this Aug 16, 2026
@aaearon
aaearon changed the base branch from test/isolation-harness to main August 16, 2026 07:37
Close the SCA / workflows / models rows of the mutation ledger.

sca: record route/body/params in mockHTTPClient; assert the exact route
for every endpoint and the full POST body contents; replace the
tautological TestListSessions_WithCSPFilter with an assertion on the
sent csp query param; pin the on-demand target_category and pageSize
literals; cover context propagation and the paginated decode errors;
extract the X-API-Version guard into its own test; pin the sca/uar ISP
service slugs via the constructed BaseURL.

workflows: drive a 500 through all six checkResponse call sites; assert
the exact finalize route and FinalizationReason; pin the limit query
param and defaultPageSize; add logging_client_test.go (including the
Authorization redaction guard) and service_config_test.go.

models: pin the requestDetails, result, cancelReason and roleId request
tags, and decode a populated accessCredentials off the wire through
ParseAWSCredentials; assert the parsed values in TestParseAWSCredentials.

No production code changed.
…rdicts

Twelve PR8 rows named tests that the implementer consolidated away. Point each
row at the test that actually exists, and say explicitly where several rows now
share one test rather than repeating a name with no note.

SCA-18 was recorded as OVERSTATED/refuted on a "not reproducible" verdict that
came from a sandbox without loopback TCP. It has now been reproduced on both
services (inbound requests = 4, want 1), so it flips to CONFIRMED/test naming
the two retry-policy tests as its killers. SCA-15's identical clause is dropped:
both X-API-Version mutants were executed and both fail.

Record the reusable lesson in the preamble: a bare deletion of
sdkclient.DisableTransientRetry orphans the import and is a compile kill, not a
test kill; the honest mutation is the assignment form. Summary counts updated.

Also: soften two test comments that claimed to replace assertions still present
elsewhere, and assert the error message in the credentials "empty string" row so
the previously inert empty-string guard is killed.
TestListRequests_SendsLimit already recorded mock.gotRoute and never asserted
it, leaving /api/workflows/requests the only unpinned route in either service.
TestSubmitRequest asserted only TargetCategory, so dropping RequestDetails at
the service boundary survived the whole suite.
GroupsElevateTarget.groupId is the whole per-target payload of
POST /api/access/elevate/groups, and GroupsElevateTargetResult.sessionId is the
only handle for revoking a group session by ID. Five tags across the request and
response models survived renaming.
The workflows models test pinned only the three request bodies while the SCA
twin pinned both directions, leaving the keys `grant request get` and
`grant request list` render free to be renamed. Form validation metadata
remains unpinned and is recorded as a follow-up in the ledger.
The workflows mock returned the same *http.Response on every Get, so the second
page of a paginating test would have read an already-drained Body. Replaced with
a per-call queue that errors clearly when exhausted.

TestServiceConfig_ReturnsIdsecServiceConfig asserted that ServiceConfig()
returns the type its signature already declares; removed from both the workflows
and SCA copies.
…ntract rows

SCA-16 cited elevate.go:28 (the response model); the request model's roleId is
at :6. WF-14 cited a test line for the cancel twin, against the preamble's rule
that File:line is always the production site — named the test instead.

Adds WF-22/WF-23 (list route, submit body), SCA-20..24 (group-elevation tags),
WF-24 (workflows response tags, closed) and WF-25 (form validation metadata,
recorded as a follow-up).
@aaearon
aaearon force-pushed the test/wire-contracts branch from 8ca095a to 04fe58c Compare August 16, 2026 07:42
@aaearon
aaearon merged commit 72a49d5 into main Aug 16, 2026
2 checks passed
@aaearon
aaearon deleted the test/wire-contracts branch August 16, 2026 13:28
aaearon added a commit that referenced this pull request Aug 16, 2026
Squash-merging seven stacked PRs (#63-#69) that each carried their own copy
of the ledger appended both the pre-work and post-work version of many rows.
48 IDs appeared twice inside the ## Ledger table. Collapse them, recompute the
summary, and rewrite the rows whose production site no longer exists.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant